home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / building.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-30  |  9.3 KB  |  375 lines

  1. #include "building.h"
  2. #include "groupai.h"
  3. #include "player.h"
  4.  
  5. std::vector<MESH*> buildingMeshes;
  6.  
  7. void LoadBuildingResources(IDirect3DDevice9* m_pDevice)
  8. {
  9.     std::vector<std::string> fnames;
  10.  
  11.     fnames.push_back("meshes/townhall_b.x");
  12.     fnames.push_back("meshes/townhall.x");
  13.     fnames.push_back("meshes/barracks_b.x");
  14.     fnames.push_back("meshes/barracks.x");
  15.     fnames.push_back("meshes/tower_b.x");
  16.     fnames.push_back("meshes/tower.x");
  17.  
  18.     for(int i=0;i<fnames.size();i++)
  19.         buildingMeshes.push_back(new MESH((char*)fnames[i].c_str(), m_pDevice));
  20. }
  21.  
  22. void UnloadBuildingResources()
  23. {
  24.     for(int i=0;i<buildingMeshes.size();i++)
  25.         if(buildingMeshes[i] != NULL)
  26.             delete buildingMeshes[i];
  27.  
  28.     buildingMeshes.clear();
  29. }
  30.  
  31. bool PlaceOk(int buildType, INTPOINT mp, TERRAIN *terrain)
  32. {
  33.     if(terrain == NULL)return false;
  34.  
  35.     BUILDING b(buildType, 0, true, mp, NULL, NULL, false, NULL);
  36.     RECT r = b.GetMapRect(2);
  37.  
  38.     for(int y=r.top;y<=r.bottom;y++)
  39.         for(int x=r.left;x<=r.right;x++)
  40.         {
  41.             //Building must be within map borders
  42.             if(!terrain->Within(INTPOINT(x,y)))return false;
  43.             MAPTILE *tile = terrain->GetTile(x, y);
  44.             if(tile == NULL)return false;
  45.  
  46.             //The terrain must be level and walkable
  47.             if(tile->m_type != 0 || !tile->m_walkable)return false;
  48.         }
  49.  
  50.     return true;
  51. }
  52.  
  53. //////////////////////////////////////////////////////////////////////////////////
  54. //                                BUILDING                                        //
  55. //////////////////////////////////////////////////////////////////////////////////
  56.  
  57. BUILDING::BUILDING(int _type, int _team, bool finished, INTPOINT mp, TERRAIN *_terrain, PLAYER *_player, bool _affectTerrain, IDirect3DDevice9* Dev)
  58. {
  59.     m_type = _type;
  60.     m_team = _team;
  61.     m_mappos = mp;
  62.     m_pTerrain = _terrain;
  63.     m_affectTerrain = _affectTerrain;
  64.     m_pDevice = Dev;    
  65.     m_range = m_damage = 0;
  66.     m_isBuilding = true;
  67.     m_deathCountDown = 0.0f;
  68.     m_training = false;
  69.     m_pPlayer = _player;
  70.     m_pTarget = NULL;    
  71.     m_pTrainingEffect = NULL;
  72.  
  73.     if(finished)
  74.     {
  75.         m_buildProgress = 1.0f;
  76.         m_meshInstance.SetMesh(buildingMeshes[m_type * 2 + 1]);
  77.     }
  78.     else
  79.     {
  80.         m_buildProgress = 0.0f;
  81.         m_meshInstance.SetMesh(buildingMeshes[m_type * 2]);
  82.     }
  83.  
  84.     if(m_type == TOWNHALL)
  85.     {
  86.         m_hp = m_hpMax = 600;
  87.         m_sightRadius = 12;
  88.         m_name = "Townhall";
  89.         m_mapsize.Set(4,2);
  90.         m_meshInstance.SetScale(D3DXVECTOR3(0.13f, 0.13f, 0.13f));
  91.         m_buildSpeed = 0.05f;
  92.     }    
  93.     else if(m_type == BARRACKS)
  94.     {
  95.         m_hp = m_hpMax = 450;
  96.         m_sightRadius = 13;
  97.         m_name = "Barracks";
  98.         m_mapsize.Set(2,4);
  99.         m_meshInstance.SetScale(D3DXVECTOR3(0.15f, 0.15f, 0.15f));
  100.         m_buildSpeed = 0.07f;
  101.     }    
  102.     else if(m_type == TOWER)
  103.     {
  104.         m_hp = m_hpMax = 750;
  105.         m_sightRadius = 20;
  106.         m_name = "Tower";
  107.         m_mapsize.Set(2,2);
  108.         m_meshInstance.SetScale(D3DXVECTOR3(0.13f, 0.13f, 0.13f));
  109.         m_buildSpeed = 0.04f;
  110.     }
  111.  
  112.     if(m_pTerrain != NULL)
  113.         m_position = m_pTerrain->GetWorldPos(m_mappos) + D3DXVECTOR3(m_mapsize.x / 2.0f, 0.0f, -m_mapsize.y / 2.0f);
  114.     else m_position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  115.  
  116.     m_meshInstance.SetPosition(m_position);
  117.  
  118.     m_BBox = m_meshInstance.GetBoundingBox();
  119.     m_BBox.max -= D3DXVECTOR3(0.2f, 0.2f, 0.2f);
  120.     m_BBox.min += D3DXVECTOR3(0.2f, 0.2f, 0.2f);
  121.  
  122.     //Update the tiles of the m_pTerrain
  123.     if(m_pTerrain != NULL && m_affectTerrain)
  124.     {
  125.         RECT mr = GetMapRect(0);
  126.  
  127.         for(int y=mr.top;y<=mr.bottom;y++)
  128.             for(int x=mr.left;x<=mr.right;x++)
  129.             {
  130.                 MAPTILE *tile = m_pTerrain->GetTile(x, y);
  131.                 if(tile != NULL)
  132.                 {
  133.                     tile->m_walkable = false;
  134.                     tile->m_pMapObject = this;
  135.                 }
  136.             }
  137.  
  138.         m_pTerrain->m_updateSight = true;
  139.         m_pTerrain->UpdatePathfinding(&GetMapRect(1));
  140.         m_pTrainingEffect = new EFFECT_TRAINING(m_pDevice);
  141.     }
  142.  
  143.     //Set m_fires positions and scales
  144.     if(m_type == TOWNHALL)
  145.     {
  146.         m_firePos[0] = m_position + D3DXVECTOR3(0.0f, 3.0f, 1.0f);
  147.         m_firePos[1] = m_position + D3DXVECTOR3(-2.0f, 1.2f, -0.4f);
  148.         m_firePos[2] = m_position + D3DXVECTOR3(2.0f, 0.0f, -1.0f);
  149.         m_fireScale[0] = D3DXVECTOR3(3.0f, 4.0f, 3.0f);
  150.         m_fireScale[1] = D3DXVECTOR3(3.0f, 8.0f, 3.0f);
  151.         m_fireScale[2] = D3DXVECTOR3(3.0f, 8.0f, 3.0f);
  152.     }    
  153.     else if(m_type == BARRACKS)
  154.     {
  155.         m_firePos[0] = m_position + D3DXVECTOR3(-0.85f, 2.5f, 0.7f);
  156.         m_firePos[1] = m_position + D3DXVECTOR3(0.5f, 0.0f, 0.0f);
  157.         m_firePos[2] = m_position + D3DXVECTOR3(0.0f, 0.0f, -2.0f);
  158.         m_fireScale[0] = D3DXVECTOR3(3.0f, 3.0f, 3.5f);
  159.         m_fireScale[1] = D3DXVECTOR3(2.0f, 2.0f, 3.5f);
  160.         m_fireScale[2] = D3DXVECTOR3(3.0f, 3.0f, 4.0f);
  161.     }    
  162.     else if(m_type == TOWER)
  163.     {
  164.         m_firePos[0] = m_position + D3DXVECTOR3(0.0f, 0.0f, 0.85f);
  165.         m_firePos[1] = m_position + D3DXVECTOR3(-0.6f, 3.0f, -0.4f);
  166.         m_firePos[2] = m_position + D3DXVECTOR3(0.0f, 5.0f, 0.0f);
  167.         m_fireScale[0] = D3DXVECTOR3(1.5f, 1.5f, 3.5f);
  168.         m_fireScale[1] = D3DXVECTOR3(1.5f, 1.5f, 2.0f);
  169.         m_fireScale[2] = D3DXVECTOR3(3.0f, 3.0f, 4.0f);
  170.     }
  171. }
  172.  
  173. BUILDING::~BUILDING()
  174. {
  175.     try
  176.     {
  177.         for(int i=0;i<m_fires.size();i++)
  178.             if(m_fires[i] != NULL)
  179.                 delete m_fires[i];
  180.         m_fires.clear();
  181.  
  182.         if(m_pTrainingEffect != NULL)
  183.             delete m_pTrainingEffect;
  184.     }
  185.     catch(...)
  186.     {
  187.         debug.Print("Error in ~BUILDING()");
  188.     }
  189. }
  190.  
  191. void BUILDING::Render()
  192. {
  193.     if(m_visible)
  194.     {
  195.         if(m_buildProgress < 1.0f)
  196.             m_meshInstance.Render(m_buildProgress);
  197.         else 
  198.         {
  199.             m_meshInstance.Render();
  200.         }
  201.     }
  202. }
  203.  
  204. void BUILDING::RenderFires()
  205. {
  206.     //Render m_fires
  207.     for(int i=0;i<m_fires.size();i++)
  208.         if(m_fires[i] != NULL)
  209.             m_fires[i]->Render();
  210. }
  211.  
  212. void BUILDING::Update(float deltaTime)
  213. {
  214.     try
  215.     {
  216.         if(m_dead)
  217.         {
  218.             m_deathCountDown += deltaTime;
  219.             m_position.y -= deltaTime;
  220.             m_meshInstance.m_pos = m_position;
  221.  
  222.             //Shrink sightradius when a unit has died
  223.             int oldSr = m_sightRadius;
  224.             if(m_sightRadius > 0.0f)m_sightRadius -= deltaTime * 2.0f;
  225.             if(m_sightRadius < 0.0f)m_sightRadius = 0.0f;
  226.             if(oldSr != (int)m_sightRadius)m_pTerrain->m_updateSight = true;
  227.         }
  228.         else
  229.         {
  230.             //Building building
  231.             if(m_buildProgress < 1.0f)
  232.             {
  233.                 m_buildProgress += deltaTime * m_buildSpeed;
  234.  
  235.                 if(m_buildProgress >= 1.0f)
  236.                 {
  237.                     m_buildProgress = 1.0f;
  238.                     m_meshInstance.SetMesh(buildingMeshes[m_type * 2 + 1]);
  239.  
  240.                     //Deploy worker unit
  241.                     if(m_pTarget != NULL)
  242.                     {
  243.                         INTPOINT from(m_mappos.x + rand()%10 - 5, m_mappos.y + rand()%10 - 5);
  244.                         INTPOINT p = GetAttackPos(from);
  245.                         if(!m_pTerrain->Within(p))
  246.                             p = m_pTerrain->GetClosestFreeTile(m_mappos, from);
  247.                         
  248.                         UNIT *unit = (UNIT*)m_pTarget;
  249.                         unit->MoveUnit(p);
  250.                         unit->m_position = m_pTerrain->GetWorldPos(p);
  251.                         m_pPlayer->m_mapObjects.push_back(unit);
  252.                         m_pTarget = NULL;
  253.                     }
  254.                 }
  255.             }
  256.             else
  257.             {
  258.                 if(m_training)
  259.                 {
  260.                     m_pTrainingEffect->Update(deltaTime);
  261.                     float progress = m_trainingTime / m_maxTrainingTime;
  262.                     m_pTrainingEffect->Set(progress, m_position + D3DXVECTOR3(0.0f, m_BBox.max.y - m_BBox.min.y + 1.5f, 0.0f));
  263.  
  264.                     m_trainingTime += deltaTime;
  265.  
  266.                     if(m_trainingTime >= m_maxTrainingTime)
  267.                     {
  268.                         m_training = false;
  269.                         INTPOINT from(m_mappos.x + rand()%10 - 5, m_mappos.y + rand()%10 - 5);
  270.                         INTPOINT p = GetAttackPos(from);
  271.                         if(!m_pTerrain->Within(p))
  272.                             p = m_pTerrain->GetClosestFreeTile(m_mappos, from);
  273.  
  274.                         UNIT *unit = (UNIT*)m_pPlayer->AddMapObject(m_trainingUnit, p, false, true);
  275.                         unit->Goto(m_pTerrain->GetClosestFreeTile(unit->m_mappos, unit->m_mappos), false, true, STATE_MOVING);
  276.                     }
  277.                 }
  278.             }
  279.         }
  280.  
  281.         //Update m_fires
  282.         for(int i=0;i<m_fires.size();i++)
  283.             if(m_fires[i] != NULL)
  284.                 m_fires[i]->Update(deltaTime);
  285.     }
  286.     catch(...)
  287.     {
  288.         debug.Print("Error in BUILDING::Update()");
  289.     }
  290. }
  291.  
  292. BBOX BUILDING::GetBoundingBox()
  293. {
  294.     return m_BBox;
  295. }
  296.  
  297. D3DXMATRIX BUILDING::GetWorldMatrix()
  298. {
  299.     return m_meshInstance.GetWorldMatrix();
  300. }
  301.  
  302. bool BUILDING::isDead()
  303. {
  304.     return m_deathCountDown > 10.0f;
  305. }
  306.  
  307. void BUILDING::Damage(int dmg, MAPOBJECT* attacker)
  308. {
  309.     if(m_dead)return;
  310.  
  311.     int oldHP = m_hp;
  312.     m_hp -= dmg;
  313.  
  314.     //Add m_fires
  315.     int limit[3] = {m_hpMax * 0.75f, m_hpMax * 0.5f, m_hpMax * 0.25f};
  316.     for(int i=0;i<3;i++)
  317.         if(m_hp < limit[i] && oldHP >= limit[i])
  318.             m_fires.push_back(new EFFECT_FIRE(m_pDevice, m_firePos[i], m_fireScale[i]));
  319.  
  320.     if(m_hp <= 0)
  321.     {
  322.         m_hp = 0;
  323.         m_dead = true;
  324.  
  325.         UNIT *attackUnit = (UNIT*)attacker;
  326.         if(attackUnit != NULL && attackUnit->m_player != NULL)
  327.             attackUnit->m_player->m_numKills++;
  328.  
  329.         //restore the tiles of the terrain
  330.         if(m_pTerrain != NULL && m_affectTerrain)
  331.         {
  332.             RECT mr = GetMapRect(0);
  333.  
  334.             for(int y=mr.top;y<=mr.bottom;y++)
  335.                 for(int x=mr.left;x<=mr.right;x++)
  336.                 {
  337.                     MAPTILE *tile = m_pTerrain->GetTile(x, y);
  338.                     if(tile != NULL)
  339.                     {
  340.                         tile->m_walkable = true;
  341.                         tile->m_pMapObject = NULL;
  342.                     }
  343.                 }
  344.  
  345.             m_pTerrain->UpdatePathfinding(&GetMapRect(1));
  346.             m_pTerrain->m_updateSight = true;
  347.         }
  348.  
  349.         //Kill m_fires
  350.         for(int i=0;i<m_fires.size();i++)
  351.             if(m_fires[i] != NULL)
  352.                 m_fires[i]->Kill();
  353.  
  354.         //Leave group
  355.         if(m_pGroup != NULL)
  356.         {
  357.             m_pGroup->RemoveMember(this);
  358.             m_pGroup = NULL;
  359.         }
  360.     }
  361. }
  362.  
  363. void BUILDING::TrainUnit(int unit)
  364. {
  365.     if(m_pPlayer->money < GetCost(unit, false))return;
  366.  
  367.     m_training = true;
  368.     m_trainingUnit = unit;
  369.     m_trainingTime = 0.0f;
  370.     m_pPlayer->money -= GetCost(unit, false);
  371.  
  372.     if(unit == WORKER)m_maxTrainingTime = 15.0f;
  373.     if(unit == SOLDIER)m_maxTrainingTime = 20.0f;
  374.     if(unit == MAGICIAN)m_maxTrainingTime = 30.0f;
  375. }